﻿/****************
 * Copyright 2016 Brian Tabone
 * Licensed under the Apache 2.0 License
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Conversation.cs
 * Class implementing the conversation endpoint
 * 9/10/2016
 */
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Web.Http;
using IAO.Common.Interfaces.MessageInterfaces;

namespace IAO.Common.Network.MessageImplementations
{
    [DataContract]
    public class ConversationMessage
    {
        [DataMember] public string Content;

        [DataMember] public Guid ConversationID;

        [DataMember] public DateTime CreateDT;

        [DataMember] public long LifetimeMS;

        [DataMember] public Guid MessageID;

        /// <summary>
        ///     If the message isn't processed by this time, it should be ignored
        /// </summary>
        [DataMember]
        public DateTime ExpirationDT
        {
            get { return CreateDT.AddMilliseconds(LifetimeMS); }
            set { new HttpResponseException(HttpStatusCode.NotImplemented); }
        }
    }

    [DataContract]
    public class Conversation : IConversation
    {
        private static readonly ConcurrentBag<Conversation> ThreadSafeConversationBag =
            new ConcurrentBag<Conversation>();

        private readonly ConcurrentQueue<ConversationMessage> ThreadSafeMessageQueue =
            new ConcurrentQueue<ConversationMessage>();

        public Conversation()
        {
            ConversationID = Guid.NewGuid();
            ThreadSafeConversationBag.Add(this);
        }

        public Conversation(ConversationMessage firstMessage)
        {
            ConversationID = firstMessage.ConversationID;
            ThreadSafeConversationBag.Add(this);
            RecieveMessage(firstMessage.MessageID, firstMessage.Content, firstMessage.LifetimeMS);
        }

        [DataMember]
        public List<ConversationMessage> Messages
        {
            get
            {
                var messages = new List<ConversationMessage>(ThreadSafeMessageQueue);

                return messages;
            }
        }


        /// <summary>
        ///     Get a list of conversations (at the moment it is called)
        /// </summary>
        public static List<Conversation> Conversations
        {
            get
            {
                var conversations = new List<Conversation>(ThreadSafeConversationBag);
                return conversations;
            }
        }

        [DataMember]
        public Guid ConversationID { get; private set; }

        [OperationContract]
        public void RecieveMessage(Guid messageId, string messageContent, long messageLifetimeMS)
        {
            var incomingMessage = new ConversationMessage
            {
                ConversationID = ConversationID,
                MessageID = messageId,
                Content = messageContent,
                LifetimeMS = messageLifetimeMS,
                CreateDT = DateTime.UtcNow
            };

            // Should we catch all exceptions or will error stack trace make it back to caller? We'll find out.

            ThreadSafeMessageQueue.Enqueue(incomingMessage);
        }

        public void SendMessage(string receiverURI, string converstionId, string messageId, string messageContent,
            long messageLifetimeMS)
        {
            throw new NotImplementedException();
        }

        private ConversationMessage GetNextMessage()
        {
            ConversationMessage nextMessage;
            if (ThreadSafeMessageQueue.TryDequeue(out nextMessage))
            {
                return nextMessage;
            }

            return null;
        }
    }
}